package com.duke.shaking.net;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.CoreConnectionPNames;
import org.json.JSONException;
import org.json.JSONObject;

import android.content.Context;
import android.util.Log;

import com.androidquery.AQuery;
import com.androidquery.callback.AjaxCallback;
import com.duke.shaking.BaseActivity;
import com.duke.shaking.Constants;
import com.duke.shaking.pojo.Message;
import com.duke.shaking.utils.AppUtils;
import com.duke.shaking.utils.DeviceUtils;
import com.duke.shaking.utils.LocationUtils;
import com.loopj.android.http.AsyncHttpClient;
import com.loopj.android.http.AsyncHttpResponseHandler;
import com.loopj.android.http.RequestParams;

/**
 * Utility class to call backend service
 * @author xiaomin
 *
 */
public class NetUtils {
	public static boolean STATIC_MODE = false;
	public static boolean NO_STATIC_MSG = true;
	public static final int DEFAULT_REQUEST_TIMEOUT = 30000;
	
	public static String CONTENT_TYPE_JSON = "application/json";
	public static String CONTENT_TYPE_MULTIPART = "multipart/form-data";
	
	public static int PHOTO_AVATAR = 1;
	public static int PHOTO_ALBUM = 2;
	
	public static String RESULT_SUCCESS = "1";
	public static int SRC_DEF = 2;
	
	/* request attribute name */
	public static String HEADER = "header";
	public static String BODY = "body";
	public static String RESULT = "result";
	
	public static String REQUEST_TYPE = "request_type";
	public static String SRC = "src";
	public static String DEVICE_ID = "deviceid";
	public static String SM_ID = "smid";
	public static String MOBILE = "mobile";
	public static String SEX = "sex";
	public static String CODE = "code";
	public static String TOKEN = "token";
	public static String PASSWORD = "passwd";
	public static String BIRTHDAY = "birthday";
	public static String NICKNAME = "nickname";
	public static String CITY_LIVE = "citylive";
	public static String JOB = "job";
	public static String SCHOOL = "school";
	public static String INTEREST = "interest";
	public static String REMARKS = "remarks";
	public static String CHOOSE_SEX = "choosesex";
	public static String STATUS = "status";
	public static String SIGN = "sign";
	public static String LBS = "lbs";
	public static String USERID = "userid";
	public static String URL = "url";
	public static String LEVEL = "level";
	public static String CITY1 = "city1";
	public static String CITY_1 = "city_1";
	public static String CITY2 = "city2";
	public static String COMPLETE = "complete";
	public static String MESSAGE = "message";
	public static String CONTENT = "content";
	public static String CREATETIME = "createtime";
	public static String PAGER = "pager";
	public static String CURRENTPAGE = "currentPage";
	public static String PAGESIZE = "pagesize";
	public static String TOTALROWS = "totalRows";
	public static String FUID = "fuid";
	public static String UPFILE = "upfile";
	public static String PHOTO = "photo";
	public static String USER = "user";
	public static String LETTERS = "letters";
	public static String ISFIRST = "isfirst";
	public static String AGE = "age";
	public static String OLDPSW = "oldpsw";
	public static String NEWPSW = "newpsw";
	public static String PID = "pid";
	public static String TYPE = "type";
	public static String NAME = "name";
	public static String ACCOUNT = "account";
	public static String ORDERID = "orderid";
	public static String ORDERTIME = "ordertime";
	public static String SIGNKEY = "sign";
	public static String PRESENT = "present";
	public static String ID = "id";
	public static String NUMS = "nums";
	public static String USED = "used";
	public static String PAYRESULT = "payresult";
	public static String VERSIONCODE = "versionCode";
	public static String VERSIONNAME = "versionName";
	public static String DOWNURL = "downurl";
	
	private static final String TAG = "NetUtils";
	
	private static JSONObject getHeaderJson(String requestId, boolean setToken) throws JSONException {
		JSONObject headerJson = new JSONObject();
		headerJson.put(REQUEST_TYPE, requestId);
		headerJson.put(SRC, SRC_DEF);
		headerJson.put(DEVICE_ID, DeviceUtils.getDeviceId());
		headerJson.put(SM_ID, DeviceUtils.getSimSerial());
		if (setToken) {
			if (BaseActivity.getMe() != null) {
				headerJson.put(TOKEN, BaseActivity.getMe().getAuthToken());
			}
			else {
				headerJson.put(TOKEN, "");
			}
		}
		return headerJson;
	}
	/**
	 * F00.00.01.02 Get verify code
	 * @param context
	 * @param responseHandler
	 */
	public static AsyncHttpClient getVerifyCode(Context context, AsyncHttpResponseHandler responseHandler, String mobile) {
        try {
			JSONObject headerJson = getHeaderJson("F00.00.01.02", false);
			JSONObject bodyJson = new JSONObject();
			bodyJson.put(MOBILE, mobile);
			return callService(context, responseHandler, headerJson, bodyJson, "getVerifyCode");
		} catch (JSONException e) {
			// TODO: handle exception
		}
        return null;
	}
	
	/**
	 * F00.00.00.03 Register user
	 * Sex: girl:1, boy: 2
	 * code is verify code
	 * @param context
	 * @param responseHandler
	 */
	public static AsyncHttpClient register(Context context, AsyncHttpResponseHandler responseHandler, Map<String, String> params) {
        try {
			JSONObject headerJson = getHeaderJson("F00.00.01.03", false);
			JSONObject bodyJson = new JSONObject();
			bodyJson.put(MOBILE, params.get(MOBILE));
			bodyJson.put(SEX, params.get(SEX));
			bodyJson.put(CODE, params.get(CODE));
			return callService(context, responseHandler, headerJson, bodyJson, "register");
		} catch (JSONException e) {
			// TODO: handle exception
		}
        return null;
	}
	
	/**
	 * F00.00.01.04 Login
	 * @param context
	 * @param responseHandler
	 * @param params
	 */
	public static AsyncHttpClient login(Context context, AsyncHttpResponseHandler responseHandler, Map<String, String> params) {
        try {
			JSONObject headerJson = getHeaderJson("F00.00.01.04", false);
			JSONObject bodyJson = new JSONObject();
			bodyJson.put(MOBILE, params.get(MOBILE));
			bodyJson.put(PASSWORD, params.get(PASSWORD));
			return callService(context, responseHandler, headerJson, bodyJson, "login");
		} catch (JSONException e) {
			// TODO: handle exception
		}
        return null;
	}
	
	/**
	 * F00.00.01.05 Update user profile
	 * @param context
	 * @param responseHandler
	 * @param params
	 */
	public static AsyncHttpClient updateProfile(Context context, AsyncHttpResponseHandler responseHandler, Map<String, String> params, ArrayList<Integer> hobbies) {
        try {
			JSONObject headerJson = getHeaderJson("F00.00.01.05", true);
			JSONObject bodyJson = new JSONObject();
			if (params != null) {
				putNotNullAttribute(bodyJson, BIRTHDAY, params.get(BIRTHDAY));
				putNotNullAttribute(bodyJson, NICKNAME, params.get(NICKNAME));
				putNotNullAttribute(bodyJson, CITY_LIVE, params.get(CITY_LIVE));
				putNotNullAttribute(bodyJson, JOB, params.get(JOB));
				putNotNullAttribute(bodyJson, SCHOOL, params.get(SCHOOL));
				putNotNullAttribute(bodyJson, REMARKS, params.get(REMARKS));
				putNotNullAttribute(bodyJson, CHOOSE_SEX, params.get(CHOOSE_SEX));
			}
			
			if(hobbies != null) {
				String str = "";
				for (Integer h : hobbies) {
					if (h != null) {
						if (!str.equals("")) {
							str += ",";
						}
						str += h;
					}
				}
				bodyJson.put(INTEREST, str);
				//JSONArray jsonArray = new JSONArray(hobbies);
				//bodyJson.put(INTEREST, jsonArray);
				
			}
			
			return callService(context, responseHandler, headerJson, bodyJson, "updateProfile");
		} catch (JSONException e) {
			// TODO: handle exception
		}
        return null;
	}
	
	/**
	 * F00.00.01.06 shake to look for a chat friend
	 * @param context
	 * @param responseHandler
	 * @param params
	 */
	public static void shaking(Context context, AsyncHttpResponseHandler responseHandler, int sexFilter) {
        try {
        	JSONObject headerJson = getHeaderJson("F00.00.01.06", true);
			headerJson.put(LBS, LocationUtils.latitude + "|" + LocationUtils.longitude);
			JSONObject bodyJson = new JSONObject();
			if (sexFilter > 0) {
				bodyJson.put(SEX, sexFilter);
			}
			callService(context, responseHandler, headerJson, bodyJson, "shaking");
        } catch(JSONException e) {
        	
        }
        
    }
	
	/**
	 * F00.00.01.07 fetch the unread messages from server
	 * this is a sync method, it would cause the caller thread be blocked
	 * @param context
	 * @param responseHandler
	 * @param params
	 */
	public static String fetchMessage(Context context, String fUserId, int maxCount) {
        try {
        	JSONObject headerJson = getHeaderJson("F00.00.01.07", true);

			JSONObject bodyJson = new JSONObject();
			bodyJson.put(FUID, fUserId);
			JSONObject pager = new JSONObject();
			pager.put(CURRENTPAGE, 0);
			pager.put(PAGESIZE, maxCount);
			pager.put(TOTALROWS, 0);
			bodyJson.put(PAGER, pager);
			if (NO_STATIC_MSG) {
				return syncCallService(context, headerJson, bodyJson, "success-empty");
			}
			else {
				return syncCallService(context, headerJson, bodyJson, "fetchMessage");
			}
        } catch(JSONException e) {
        	
        }
        return null;
    }
	
	/**
	 * Upload photo 
	 * @param context
	 * @param type Equals to 1 if avatar, equals to 2 if album photo
	 * @param params
	 * @param responseHandler
	 */
	public static AsyncHttpClient uploadPhoto(Context context, int type, Map<String, String> params, AsyncHttpResponseHandler responseHandler) {
		String url = AppUtils.getUploadPhotoUrl();
		url += "?token=" + params.get(TOKEN);
		url += "&src=" + SRC_DEF;
		url += "&type=" + type;
		Log.i(TAG, "upload photo url:" + url);
		try {
			RequestParams requestParams = new RequestParams();
			File file = new File(params.get(UPFILE));
			requestParams.put(UPFILE, file);
			//Header header = new BasicHeader("Content-Type", CONTENT_TYPE_MULTIPART);
			callService(context, url, null, CONTENT_TYPE_MULTIPART, requestParams, responseHandler, "uploadPhoto");
			//return callService(context, url, CONTENT_TYPE_MULTIPART, requestParams, responseHandler, "uploadPhoto");
		} catch (FileNotFoundException e) {
			Log.e(TAG, "File to be uploaded not found");
		}
		return null;
	}
	
	/**
	 * Upload photo
	 * @param context
	 * @param type
	 * @param params
	 * @return
	 * Sample response:
	 * {"pid":"39",
	 *  "url":"http://file.love5.cn/getfile/I-6WEg+TeS==.jpg",
	 *  "url_1":"http://img.love5.cn/img/100x100/i/e/e/I-6WEg+TeS==.jpg",
	 *  "url_5":"http://img.love5.cn/img/50x50/i/e/e/I-6WEg+TeS==.jpg",
	 *  "url_6":"http://img.love5.cn/img/600x600/i/e/e/I-6WEg+TeS==.jpg"}
	 */
	/*public static String uploadPhoto(Context context, int type, Map<String, String> params) {
		String url = AppUtils.getUploadPhotoUrl();
		url += "?token=" + params.get(TOKEN);
		url += "&src=" + SRC_DEF;
		url += "&type=" + type;
		Log.i(TAG, "upload photo url:" + url);
		File file = new File(params.get(UPFILE));
		try {
			InputStream is = new FileInputStream(file);
			HttpClient httpClient = new DefaultHttpClient();
			HttpPost postRequest = new HttpPost(url);
			byte[] data = IOUtils.toByteArray(is);
			InputStreamBody isb = new InputStreamBody(
					new ByteArrayInputStream(data), params.get(UPFILE));
			MultipartEntity multipartEntity = new MultipartEntity();
			multipartEntity.addPart(UPFILE, isb);
			postRequest.setEntity(multipartEntity);
			HttpResponse response = httpClient.execute(postRequest);
			if(response.getStatusLine().getStatusCode() == 200) {
				HttpEntity entity = response.getEntity();
				return EntityUtils.toString(entity);
			} else {
				return null;
			}
			
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO: handle exception
		}
		return null;
	}*/
	
	public static AQuery uploadPhoto(Context context, int type, Map<String, String> params, AjaxCallback<JSONObject> ajaxCallback) {
		String url = AppUtils.getUploadPhotoUrl();
		url += "?token=" + params.get(TOKEN);
		url += "&src=" + SRC_DEF;
		url += "&type=" + type;
		Log.i(TAG, "upload photo url:" + url);
		
        Map<String, Object> requestParams = new HashMap<String, Object>();
        
        File file = new File(params.get(UPFILE));
        requestParams.put(UPFILE, file);
        
        AQuery aq = new AQuery(context);
        AjaxCallback.setTimeout(DEFAULT_REQUEST_TIMEOUT);
        return aq.ajax(url, requestParams, JSONObject.class, ajaxCallback);
	}
	
	/**
	 * F00.00.01.11 fetch the all messages from server
	 * this is a sync method, it would cause the caller thread be blocked
	 * @param context
	 * @param responseHandler
	 * @param params
	 */
	public static String fetchAllFriends(Context context, int maxCount) {
        try {
        	JSONObject headerJson = getHeaderJson("F00.00.01.11", true);

			JSONObject bodyJson = new JSONObject();
			JSONObject pager = new JSONObject();
			pager.put(PAGESIZE, maxCount);
			bodyJson.put(PAGER, pager);
			if (NO_STATIC_MSG) {
				return syncCallService(context, headerJson, bodyJson, "success-empty");
			}
			else {
				return syncCallService(context, headerJson, bodyJson, "fetchUnreadFriends");
			}
        } catch(JSONException e) {
        	
        }
        return null;
    }
	
	/**
	 * F00.00.01.12 fetch the unread messages from server
	 * this is a sync method, it would cause the caller thread be blocked
	 * @param context
	 * @param responseHandler
	 * @param params
	 */
	public static String fetchUnreadFriends(Context context, int maxCount) {
        try {
        	JSONObject headerJson = getHeaderJson("F00.00.01.12", true);

			JSONObject bodyJson = new JSONObject();
			JSONObject pager = new JSONObject();
			pager.put(PAGESIZE, maxCount);
			bodyJson.put(PAGER, pager);
			if (NO_STATIC_MSG) {
				return syncCallService(context, headerJson, bodyJson, "success-empty");
			}
			else {
				return syncCallService(context, headerJson, bodyJson, "fetchUnreadFriends");
			}
        } catch(JSONException e) {
        	
        }
        return null;
    }
	
	/**
	 * F00.00.01.14 send a message to another user
	 * @param context
	 * @param responseHandler
	 * @param params
	 */
	public static void sendMessage(Context context, AsyncHttpResponseHandler responseHandler, Message message) {
        try {
        	JSONObject headerJson = getHeaderJson("F00.00.01.14", true);
			JSONObject bodyJson = new JSONObject();
			bodyJson.put(FUID, message.getToId());
			bodyJson.put(CONTENT, message.getContent());
			callService(context, responseHandler, headerJson, bodyJson, "sendMessage");
        } catch(JSONException e) {
        	
        }
        
    }
	
	public static String sendMessage(Context context, Message message) {
        try {
        	JSONObject headerJson = getHeaderJson("F00.00.01.14", true);
			JSONObject bodyJson = new JSONObject();
			bodyJson.put(FUID, message.getToId());
			bodyJson.put(CONTENT, message.getContent());
			return syncCallService(context, headerJson, bodyJson, "sendMessage");
        } catch(JSONException e) {
        	
        }
        return null;
    }
	
	/**
	 * F00.00.01.19 Forget password and send SMS to phone
	 * @param context
	 * @param responseHandler
	 */
	public static AsyncHttpClient forgetPassword(Context context, AsyncHttpResponseHandler responseHandler) {
		try {
			JSONObject headerJson = getHeaderJson("F00.00.01.19", true);
			JSONObject bodyJson = new JSONObject();
			return callService(context, responseHandler, headerJson, bodyJson, "forgetPassword");
		} catch (JSONException e) {
			// TODO: handle exception
		}
		return null;
	}
	
	/**
	 * F00.00.01.17 Change password
	 * @param context
	 * @param responseHandler
	 */
	public static AsyncHttpClient changePassword(Context context, AsyncHttpResponseHandler responseHandler, Map<String, String> params) {
		try {
			JSONObject headerJson = getHeaderJson("F00.00.01.17", true);
			JSONObject bodyJson = new JSONObject();
			bodyJson.put(OLDPSW, params.get(OLDPSW));
			bodyJson.put(NEWPSW, params.get(NEWPSW));
			return callService(context, responseHandler, headerJson, bodyJson, "changePassword");
		} catch (JSONException e) {
			// TODO: handle exception
		}
		return null;
	}
	
	/**
	 * F00.00.01.13 Delete a friend
	 * @param context
	 * @param responseHandler
	 */
	public static AsyncHttpClient deleteFriend(Context context, AsyncHttpResponseHandler responseHandler, String friendUId) {
		try {
			JSONObject headerJson = getHeaderJson("F00.00.01.13", true);
			JSONObject bodyJson = new JSONObject();
			bodyJson.put(FUID, friendUId);
			return callService(context, responseHandler, headerJson, bodyJson, "deleteFriend");
		} catch (JSONException e) {
			// TODO: handle exception
		}
		return null;
	}
	
	/**
	 * F00.00.01.09 Get all photos
	 * @param context
	 * @param responseHandler
	 * @param params
	 */
	public static void getPhotos(Context context, AsyncHttpResponseHandler responseHandler, Map<String, String> params) {
		try {
			JSONObject headerJson = getHeaderJson("F00.00.01.09", true);
			JSONObject bodyJson = new JSONObject();
			if(params.get(FUID) != null) {
				bodyJson.put(FUID, params.get(FUID));
			} else {
				bodyJson.put(FUID, "");
			}
			JSONObject pager = new JSONObject();
			pager.put(PAGESIZE, 100);
			pager.put(TOTALROWS, 0);
			pager.put(CURRENTPAGE, 0);
			bodyJson.put(PAGER, pager);
			callService(context, responseHandler, headerJson, bodyJson, "getPhotos");
		} catch (JSONException e) {
			// TODO: handle exception
		}
	}
	
	/**
	 * F00.00.01.16 Delete photo
	 * @param context
	 * @param responseHandler
	 * @param params
	 */
	public static AsyncHttpClient deletePhoto(Context context, AsyncHttpResponseHandler responseHandler, Map<String, String> params) {
		try {
			JSONObject headerJson = getHeaderJson("F00.00.01.16", true);
			JSONObject bodyJson = new JSONObject();
			bodyJson.put(PID, params.get(PID));
			return callService(context, responseHandler, headerJson, bodyJson, "deletePhoto");
		} catch (JSONException e) {
			// TODO: handle exception
		}
		return null;
	}
	
	/**
	 * F00.00.01.15 Buy service (upgrade to VIP)
	 * @param context
	 * @param responseHandler
	 * @param params
	 */
	public static void buyService(Context context, AsyncHttpResponseHandler responseHandler, int pid) {
		try {
			JSONObject headerJson = getHeaderJson("F00.00.01.15", true);
			JSONObject bodyJson = new JSONObject();
			bodyJson.put(PID, pid);
			callService(context, responseHandler, headerJson, bodyJson, "buyService");
		} catch (JSONException e) {
			// TODO: handle exception
		}
	}
	
	/**
	 * F00.00.01.20 get account info
	 * @param context
	 * @param responseHandler
	 */
	public static AsyncHttpClient getAccountInfo(Context context, AsyncHttpResponseHandler responseHandler) {
		try {
			JSONObject headerJson = getHeaderJson("F00.00.01.20", true);
			JSONObject bodyJson = new JSONObject();
			return callService(context, responseHandler, headerJson, bodyJson, "getAccountInfo");
		} catch (JSONException e) {
			// TODO: handle exception
		}
		return null;
	}
	
	/**
	 * F00.00.01.18 get coins
	 * @param context
	 * @param responseHandler
	 */
	public static AsyncHttpClient getFreeCoins(Context context, AsyncHttpResponseHandler responseHandler, int type, String appName) {
		try {
			JSONObject headerJson = getHeaderJson("F00.00.01.18", true);
			JSONObject bodyJson = new JSONObject();
			bodyJson.put(TYPE, type);
			bodyJson.put(NAME, appName);
			return callService(context, responseHandler, headerJson, bodyJson, "getFreeCoins");
		} catch (JSONException e) {
			// TODO: handle exception
		}
		return null;
	}
	
	/**
	 * F00.00.01.21 create an order
	 * @param context
	 * @param responseHandler
	 */
	public static AsyncHttpClient createOrder(Context context, AsyncHttpResponseHandler responseHandler, 
			String productType) {
		try {
			JSONObject headerJson = getHeaderJson("F00.00.01.21", true);
			JSONObject bodyJson = new JSONObject();
			bodyJson.put(TYPE, productType);
			return callService(context, responseHandler, headerJson, bodyJson, "createOrder");
		} catch (JSONException e) {
			// TODO: handle exception
		}
		return null;
	}
	
	/**
	 * F00.00.01.23 query an order
	 * @param context
	 * @param responseHandler
	 */
	public static AsyncHttpClient queryOrder(Context context, AsyncHttpResponseHandler responseHandler, 
			String orderNo) {
		try {
			JSONObject headerJson = getHeaderJson("F00.00.01.23", true);
			JSONObject bodyJson = new JSONObject();
			bodyJson.put(ORDERID, orderNo);
			return callService(context, responseHandler, headerJson, bodyJson, "queryOrder");
		} catch (JSONException e) {
			// TODO: handle exception
		}
		return null;
	}
	
	/**
	 * F00.00.01.08 Get friend info
	 * @param context
	 * @param responseHandler
	 * @param fuid Friend user id
	 */
	public static AsyncHttpClient getFriendInfo(Context context, AsyncHttpResponseHandler responseHandler, String fuid) {
		try {
			JSONObject headerJson = getHeaderJson("F00.00.01.08", true);
			JSONObject bodyJson = new JSONObject();
			bodyJson.put(FUID, fuid);
			return callService(context, responseHandler, headerJson, bodyJson, "getFriendInfo");
		} catch (JSONException e) {
			// TODO: handle exception
		}
		return null;
	}
	
	public static String syncCallService(Context context, JSONObject headerJson, JSONObject bodyJson, String methodName) {
		if(STATIC_MODE && methodName != null && methodName.trim().length() > 0) {
			String docsDir = AppUtils.getDummyDataDir();
			StaticDocReader reader = new StaticDocReader();
			try {
				// Just for debug purpose, will be removed
				if(Constants.DEBUG_MODE) {
					JSONObject json = new JSONObject();
					if(headerJson != null) {
						json.put(HEADER, headerJson);
					}
					if(bodyJson != null) {
						json.put(BODY, bodyJson);
					}
					StringEntity entity = new StringEntity(json.toString());
					Log.i(TAG, "Request JSON:" + json.toString());
				}
			} catch (UnsupportedEncodingException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (JSONException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			Log.i(TAG, "doc path:" + (docsDir + "/" + methodName + ".json"));
			
			return reader.read(context, docsDir + "/" + methodName + ".json", CONTENT_TYPE_JSON);
		} else {
			BufferedReader reader = null;
			
			try {
				String url = AppUtils.getServerUrl();
				HttpClient client = new DefaultHttpClient();
				HttpPost request = new HttpPost(url);
				JSONObject json = new JSONObject();
				if(headerJson != null) {
					json.put(HEADER, headerJson);
				}
				if(bodyJson != null) {
					json.put(BODY, bodyJson);
				}
				ByteArrayEntity entity = new ByteArrayEntity(json.toString().getBytes("utf-8"));
				request.setEntity(entity);
//				Log.i(TAG, "Request JSON:" + json.toString());
				client.getParams().setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 10000); 
				client.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT, 20000);
				HttpResponse response = client.execute(request);
				
				if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
//					Log.d(TAG, "asynCallService response");
					reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
					StringBuilder sb = new StringBuilder();
					for (String s = reader.readLine(); s != null; s = reader.readLine()) {
						sb.append(s);
					}
					return sb.toString();
				}
			} catch (ClientProtocolException e) {
				Log.e(TAG, e.getMessage(), e);
			} catch (IOException e) {
				Log.e(TAG, e.getMessage(), e);
			} catch (JSONException e) {
				Log.e(TAG, e.getMessage(), e);
			}
			finally {
				try {
					if (reader != null) {
						reader.close();
					}
				} catch (IOException e) {
					// ignore me
				}
			}
		}
		return null;
	}
	
	/**
	 * Internal method to call post service
	 * Get the RequestParams as the request body
	 * @param context
	 * @param url
	 * @param responseHandler
	 * @param requestParams
	 * @param methodName
	 */
	private static AsyncHttpClient callService(Context context, String url, 
			Header[] headers,
			String contentType, RequestParams params, 
			AsyncHttpResponseHandler responseHandler, String methodName) {
		if(STATIC_MODE && methodName != null && methodName.trim().length() > 0) {
			String docsDir = AppUtils.getDummyDataDir();
			StaticDocReader reader = new StaticDocReader();
			Log.i(TAG, "doc path:" + (docsDir + "/" + methodName + ".json"));
			reader.post(context, docsDir + "/" + methodName + ".json", contentType, responseHandler);
			return null;
		} else {
			AsyncHttpClient client = new AsyncHttpClient();
			client.setTimeout(DEFAULT_REQUEST_TIMEOUT);
			client.post(context, url, null, params, contentType, responseHandler);
			return client;
		}
	}

	/**
	 * Internal method to call service
	 * Get header and body JSON to call post service with an arg StringEntity
	 * @param context
	 * @param responseHandler
	 * @param headerJson
	 * @param bodyJson
	 */
	private static AsyncHttpClient callService(Context context, AsyncHttpResponseHandler responseHandler, 
			JSONObject headerJson, JSONObject bodyJson, String methodName) {
		if(STATIC_MODE && methodName != null && methodName.trim().length() > 0) {
			String docsDir = AppUtils.getDummyDataDir();
			StaticDocReader reader = new StaticDocReader();
			try {
				// Just for debug purpose, will be removed
				if(Constants.DEBUG_MODE) {
					JSONObject json = new JSONObject();
					if(headerJson != null) {
						json.put(HEADER, headerJson);
					}
					if(bodyJson != null) {
						json.put(BODY, bodyJson);
					}
					StringEntity entity = new StringEntity(json.toString());
					Log.i(TAG, "Request JSON:" + json.toString());
				}
			} catch (UnsupportedEncodingException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (JSONException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			Log.i(TAG, "doc path:" + (docsDir + "/" + methodName + ".json"));
			reader.post(context, docsDir + "/" + methodName + ".json", CONTENT_TYPE_JSON, responseHandler);
			return null;
		} else {
			String url = AppUtils.getServerUrl();
			try {
				AsyncHttpClient client = new AsyncHttpClient();
				JSONObject json = new JSONObject();
				if(headerJson != null) {
					json.put(HEADER, headerJson);
				}
				if(bodyJson != null) {
					json.put(BODY, bodyJson);
				}
				
				// Fix the Chinese to be unreadable characters issue
				byte[] bytes = json.toString().getBytes("utf-8");
				ByteArrayEntity entity = new ByteArrayEntity(bytes);
				
//				StringEntity entity = new StringEntity(json.toString());
				Log.i(TAG, "Request JSON:" + json.toString());
				client.setTimeout(DEFAULT_REQUEST_TIMEOUT);
				client.post(context, url, entity, CONTENT_TYPE_JSON, responseHandler);
				return client;
			} catch (UnsupportedEncodingException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (JSONException e) {
				// TODO: handle exception
			}
		}
		return null;
	}
	
	/**
	 * Add not null string value to JSON
	 * @param jsonObj
	 * @param name
	 * @param value
	 * @throws JSONException
	 */
	private static void putNotNullAttribute(JSONObject jsonObj, String name, String value) 
			throws JSONException {
		if(value != null) {
			jsonObj.put(name, value);
		}
	}
}
